import os
import tkinter as tk
import traceback
from tkinter import filedialog, messagebox, ttk
import os
import re

import bibtexparser
from bibtexparser.bparser import BibTexParser


def format_authors(authors_str):
    """Format authors as Last name + First initial"""
    if not authors_str:
        return ""

    authors_list = authors_str.split(" and ")
    formatted_authors = []

    for author in authors_list:
        # Handle "Last, First" format
        if ',' in author:
            last_name, first_names = author.split(',', 1)
            first_names = first_names.strip()
            # Get initials
            initials = ''.join([name[0] for name in first_names.split() if name])
            formatted_authors.append(f"{last_name.strip()} {initials}")
        else:
            # Handle "First Last" format
            names = author.split()
            if len(names) >= 2:
                last_name = names[-1]
                first_names = names[:-1]
                initials = ''.join([name[0] for name in first_names if name])
                formatted_authors.append(f"{last_name.strip()} {initials}")
            else:
                # Single name case
                formatted_authors.append(names[0])

    return ", ".join(formatted_authors)


def process_title(title):
    """Process title and remove curly braces"""
    if not title:
        return ""

    title = title.strip()
    if title.startswith('{') and title.endswith('}'):
        title = title[1:-1]

    # Remove any remaining braces that might be used for capitalization
    title = title.replace('{', '').replace('}', '')

    return title


def determine_publication_type(entry_type):
    """Determine the appropriate publication type marker based on entry type"""
    type_mapping = {
        'article': '[J]',  # Journal
        'inproceedings': '[C]',  # Conference
        'conference': '[C]',  # Conference
        'book': '[M]',  # Monograph
        'phdthesis': '[D]',  # Dissertation
        'mastersthesis': '[D]',  # Dissertation
        'techreport': '[R]',  # Report
        'misc': '[Z]',  # Miscellaneous
        'unpublished': '[Z]',  # Unpublished
    }
    return type_mapping.get(entry_type, '[J]')  # Default to journal if unknown


def convert_bibtex_to_bibitem(bibtex_file, output_file):
    try:
        with open(bibtex_file, 'r', encoding='utf-8') as bibfile:
            parser = BibTexParser()
            parser.ignore_nonstandard_types = False
            bib_database = bibtexparser.load(bibfile, parser)

        with open(output_file, 'w', encoding='utf-8') as outfile:
            for entry in bib_database.entries:
                try:
                    citation_key = entry.get('ID', '')
                    if not citation_key:
                        print(f"Warning: Entry missing citation key, skipping: {entry}")
                        continue

                    # Format authors - use empty string if missing
                    authors = format_authors(entry.get('author', ''))

                    # Process title - use empty string if missing
                    title = process_title(entry.get('title', ''))

                    # Get publication type
                    entry_type = entry.get('ENTRYTYPE', '').lower()
                    pub_type_marker = determine_publication_type(entry_type)

                    # Get year - use empty string if missing
                    year = entry.get('year', '')

                    # Get DOI if available
                    doi = entry.get('doi', '')

                    # Get pages if available
                    pages = entry.get('pages', '')
                    pages_text = f": {pages}" if pages else ""

                    # Get journal/booktitle/publisher
                    journal = entry.get('journal', '')
                    booktitle = entry.get('booktitle', '')
                    publisher = entry.get('publisher', '')
                    organization = entry.get('organization', '')

                    # Choose the appropriate venue information
                    venue = journal or booktitle or publisher or organization or ""
                    venue_text = f". {venue}" if venue else ""

                    # Build the bibitem string following GB/T 7714-2015 format
                    bibitem = f"\\bibitem{{{citation_key}}}\n"
                    bibitem += f"{authors}. " if authors else ""
                    bibitem += f"{title}" if title else ""
                    bibitem += f"{pub_type_marker}"
                    bibitem += venue_text

                    if year:
                        bibitem += f", {year}"

                    bibitem += f"{pages_text}"

                    if doi:
                        bibitem += f". DOI:{doi}"

                    bibitem += ".\n\n"

                    outfile.write(bibitem)
                except Exception as e:
                    print(f"Error processing entry {entry.get('ID', 'unknown')}: {e}")
                    traceback.print_exc()

            print(f"Processed {len(bib_database.entries)} entries")

        return True
    except Exception as e:
        print(f"Conversion failed: {e}")
        traceback.print_exc()
        return False


class BibTexConverterApp:
    def __init__(self, root):
        self.root = root
        self.root.title("BibTeX to BibItem Converter")
        self.root.geometry("600x400")
        self.root.resizable(True, True)

        self.create_widgets()

    def create_widgets(self):
        # Create a main frame
        main_frame = ttk.Frame(self.root, padding="20")
        main_frame.pack(fill=tk.BOTH, expand=True)

        # Title label
        title_label = ttk.Label(main_frame, text="BibTeX to BibItem Converter", font=("Helvetica", 16))
        title_label.pack(pady=10)

        # Input file selection
        input_frame = ttk.Frame(main_frame)
        input_frame.pack(fill=tk.X, pady=10)

        input_label = ttk.Label(input_frame, text="Input BibTeX file:")
        input_label.pack(side=tk.LEFT, padx=5)

        self.input_path_var = tk.StringVar()
        input_entry = ttk.Entry(input_frame, textvariable=self.input_path_var, width=40)
        input_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)

        browse_input_button = ttk.Button(input_frame, text="Browse", command=self.browse_input_file)
        browse_input_button.pack(side=tk.LEFT, padx=5)

        # Output file selection
        output_frame = ttk.Frame(main_frame)
        output_frame.pack(fill=tk.X, pady=10)

        output_label = ttk.Label(output_frame, text="Output file path:")
        output_label.pack(side=tk.LEFT, padx=5)

        self.output_path_var = tk.StringVar()
        output_entry = ttk.Entry(output_frame, textvariable=self.output_path_var, width=40)
        output_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)

        browse_output_button = ttk.Button(output_frame, text="Browse", command=self.browse_output_file)
        browse_output_button.pack(side=tk.LEFT, padx=5)

        # Convert button
        convert_button = ttk.Button(main_frame, text="Convert", command=self.perform_conversion)
        convert_button.pack(pady=20)

        # Status message
        self.status_var = tk.StringVar()
        status_label = ttk.Label(main_frame, textvariable=self.status_var, wraplength=500)
        status_label.pack(pady=10)

        # Preview area
        preview_frame = ttk.LabelFrame(main_frame, text="Preview")
        preview_frame.pack(fill=tk.BOTH, expand=True, pady=10)

        self.preview_text = tk.Text(preview_frame, height=10, wrap=tk.WORD)
        self.preview_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        # Scrollbar for preview
        scrollbar = ttk.Scrollbar(self.preview_text, command=self.preview_text.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.preview_text.config(yscrollcommand=scrollbar.set)

    def browse_input_file(self):
        file_path = filedialog.askopenfilename(
            title="Select BibTeX file",
            filetypes=[("BibTeX files", "*.bib"), ("All files", "*.*")]
        )
        if file_path:
            self.input_path_var.set(file_path)
            self.update_output_path(file_path)
            self.load_preview(file_path)

    def browse_output_file(self):
        file_path = filedialog.asksaveasfilename(
            title="Save output file",
            defaultextension=".txt",
            filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
        )
        if file_path:
            self.output_path_var.set(file_path)

    def update_output_path(self, input_path):
        """Auto-generate output path based on input path"""
        if input_path:
            directory = os.path.dirname(input_path)
            filename = os.path.splitext(os.path.basename(input_path))[0]
            default_output = os.path.join(directory, f"{filename}_bibitem.txt")
            self.output_path_var.set(default_output)

    def load_preview(self, file_path):
        """Load the first few lines of the BibTeX file for preview"""
        try:
            with open(file_path, 'r', encoding='utf-8') as file:
                preview_text = file.read(1000)  # Read first 1000 characters

            self.preview_text.delete(1.0, tk.END)
            self.preview_text.insert(tk.END, preview_text)
            self.status_var.set("BibTeX file loaded successfully. Click 'Convert' to proceed.")
        except Exception as e:
            self.status_var.set(f"Error loading file: {str(e)}")

    def perform_conversion(self):
        """Execute the conversion process"""
        input_path = self.input_path_var.get()
        output_path = self.output_path_var.get()

        if not input_path or not output_path:
            self.status_var.set("Please select both input and output files.")
            return

        success = convert_bibtex_to_bibitem(input_path, output_path)

        if success:
            self.status_var.set(f"Conversion successful! Output saved to: {output_path}")

            # Show preview of converted file
            try:
                with open(output_path, 'r', encoding='utf-8') as file:
                    result_text = file.read(2000)  # Read first 2000 characters

                self.preview_text.delete(1.0, tk.END)
                self.preview_text.insert(tk.END, result_text)

                # Ask if user wants to open the output file
                if messagebox.askyesno("Conversion Complete", "Do you want to open the output file?"):
                    self.open_output_file(output_path)
            except Exception as e:
                self.status_var.set(f"Conversion successful, but error displaying result: {str(e)}")
        else:
            self.status_var.set("Conversion failed. Check the input file and try again.")

    def open_output_file(self, file_path):
        """Open the output file using the default system application"""
        try:
            import platform
            import subprocess

            if platform.system() == 'Windows':
                os.startfile(file_path)
            elif platform.system() == 'Darwin':  # macOS
                subprocess.call(('open', file_path))
            else:  # Linux
                subprocess.call(('xdg-open', file_path))
        except Exception as e:
            messagebox.showerror("Error", f"Could not open file: {str(e)}")


if __name__ == "__main__":
    root = tk.Tk()
    app = BibTexConverterApp(root)
    root.mainloop()